package gat.domain.service.tg.impl;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import gat.dto.res.tg.UserBotResDto;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bitsun.core.common.exception.AppException;

import cn.hutool.core.collection.CollectionUtil;
import gat.application.tg.UserBotService;
import gat.common.util.CurrentThread;
import gat.common.util.MyStreamUtil;
import gat.domain.service.tg.ReportService;
import gat.dto.req.report.QueryOrderReq;
import gat.dto.res.report.ReportOrderRes;
import gat.infrastructure.persistence.dao.tg.AccountOrderMapper;
import gat.infrastructure.persistence.dao.tg.ChatBindRecordMapper;
import gat.infrastructure.persistence.po.tg.AccountOrderPo;
import gat.infrastructure.persistence.po.tg.ChatBindRecordPo;
import gat.infrastructure.persistence.po.tg.UserBotPo;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 你先别说话
 * @date 2025/3/31
 */
@Slf4j
@Service
public class ReportServiceImpl implements ReportService {

    @Resource
    private AccountOrderMapper accountOrderMapper;
    @Resource
    private UserBotService userBotService;
    @Resource
    private ChatBindRecordMapper chatBindRecordMapper;

    private static final String tencent = "tencent";
    private static final String ali = "ali";

    @Override
    public ReportOrderRes overview(QueryOrderReq params) {
        List<AccountOrderPo> accountOrderPos = queryByParams(params);
        List<ChatBindRecordPo> chatBindRecordPos = bindList(params);
        return list2Res(accountOrderPos, chatBindRecordPos);
    }

    @Override
    public Map<String, ReportOrderRes> queryDaily(QueryOrderReq params) {
        List<AccountOrderPo> accountOrderPos = queryByParams(params);
        List<ChatBindRecordPo> chatBindRecordPos = bindList(params);

        Map<String, List<AccountOrderPo>> orderMap = new HashMap<>();
        if (!CollectionUtil.isEmpty(accountOrderPos)) {
            orderMap = accountOrderPos.stream().collect(Collectors
                    .groupingBy(obj -> obj.getCreateTime().atZone(ZoneId.systemDefault()).toLocalDate().toString()));
        }

        Map<String, List<ChatBindRecordPo>> bindMap = new HashMap<>();
        if (!CollectionUtil.isEmpty(chatBindRecordPos)) {
            bindMap = chatBindRecordPos.stream().collect(Collectors
                    .groupingBy(obj -> obj.getCreateTime().atZone(ZoneId.systemDefault()).toLocalDate().toString()));
        }
        List<String> days = rangeDate(params.getDays());
        Map<String, ReportOrderRes> result = new LinkedHashMap<>();
        for (String day : days) {
            result.put(day, list2Res(orderMap.get(day), bindMap.get(day)));
        }
        return result;
    }

    @Override
    public Map<String, ReportOrderRes> queryBot(QueryOrderReq params) {
        List<AccountOrderPo> accountOrderPos = queryByParams(params);
        List<ChatBindRecordPo> chatBindRecordPos = bindList(params);

        Map<String, List<AccountOrderPo>> orderMap = new HashMap<>();
        if (!CollectionUtil.isEmpty(accountOrderPos)) {
            orderMap = accountOrderPos.stream().collect(Collectors
                    .groupingBy(AccountOrderPo::getBotId));
        }

        Map<String, List<ChatBindRecordPo>> bindMap = new HashMap<>();
        if (!CollectionUtil.isEmpty(chatBindRecordPos)) {
            bindMap = chatBindRecordPos.stream().collect(Collectors
                    .groupingBy(ChatBindRecordPo::getBotId));
        }

        // 获取所有机器人
        Map<String, ReportOrderRes> result = new LinkedHashMap<>();
        List<UserBotPo> botPoList = userBotService.selectAll();
        for (UserBotPo bot : botPoList) {
            result.put(bot.getBotId(), list2Res(orderMap.get(bot.getBotId()), bindMap.get(bot.getBotId())));
        }
        return result;
    }

    @Override
    public Map<String, ReportOrderRes> querySupplier(QueryOrderReq params) {
        List<AccountOrderPo> accountOrderPos = queryByParams(params);
        List<ChatBindRecordPo> chatBindRecordPos = bindList(params);

        Map<String, List<AccountOrderPo>> orderMap = new HashMap<>();
        if (!CollectionUtil.isEmpty(accountOrderPos)) {
            orderMap = accountOrderPos.stream().collect(Collectors
                    .groupingBy(AccountOrderPo::getAccountSupplier));
        }

        Map<String, List<ChatBindRecordPo>> bindMap = new HashMap<>();
        if (!CollectionUtil.isEmpty(chatBindRecordPos)) {
            bindMap = chatBindRecordPos.stream().collect(Collectors
                    .groupingBy(ChatBindRecordPo::getAccountSupplier));
        }
        Map<String, ReportOrderRes> result = new LinkedHashMap<>();

        result.put(tencent, list2Res(orderMap.get(tencent), bindMap.get(tencent)));
        result.put(ali, list2Res(orderMap.get(ali), bindMap.get(ali)));
        return result;
    }

    private ReportOrderRes list2Res(List<AccountOrderPo> accountOrderPos, List<ChatBindRecordPo> chatBindRecordPos) {
        ReportOrderRes result = new ReportOrderRes();
        if (!CollectionUtil.isEmpty(accountOrderPos)) {
            result.setTotalCount(accountOrderPos.size());
            result.setRechargeCount(MyStreamUtil.filter(accountOrderPos, a -> a.getOrderType() == 2).size());
            result.setNewBuyCount(MyStreamUtil.filter(accountOrderPos, a -> a.getOrderType() == 1).size());
            result.setTotalAmount(MyStreamUtil.longSum(accountOrderPos, AccountOrderPo::getOrderAmount));
        }
        if (!CollectionUtil.isEmpty(chatBindRecordPos)) {
            result.setBindCount(chatBindRecordPos.size());
        }
        return result;
    }

    private List<AccountOrderPo> queryByParams(QueryOrderReq params) {

        LambdaQueryWrapper<AccountOrderPo> query = new LambdaQueryWrapper<AccountOrderPo>();
        String username = CurrentThread.getCurrentUser().getUsername();

        if (!StringUtils.equals(username, "admin")) {
            UserBotResDto userBotPo = userBotService.getUserBotByUserCode(CurrentThread.getCurrentUser().getUserCode());
            if (Objects.isNull(userBotPo)) {
                throw new AppException("用户未关联机器人");
            }
            query.eq(AccountOrderPo::getBotId, userBotPo.getBotId());
        }
        query.eq(AccountOrderPo::getOrderStatus, 1);
        query.between(AccountOrderPo::getCreateTime, LocalDate.now().minusDays(params.getDays() - 1).atStartOfDay(),
                LocalDate.now().atTime(LocalTime.MAX));

        if (!Objects.isNull(params.getOrderType())) {
            query.eq(AccountOrderPo::getOrderType, params.getOrderType());
        }
        return accountOrderMapper.selectList(query);
    }

    private List<ChatBindRecordPo> bindList(QueryOrderReq params) {
        LambdaQueryWrapper<ChatBindRecordPo> query = new LambdaQueryWrapper<ChatBindRecordPo>();
        String username = CurrentThread.getCurrentUser().getUsername();

        if (!StringUtils.equals(username, "admin")) {
            UserBotResDto userBotPo = userBotService.getUserBotByUserCode(CurrentThread.getCurrentUser().getUserCode());
            if (Objects.isNull(userBotPo)) {
                throw new AppException("用户未关联机器人");
            }
            query.eq(ChatBindRecordPo::getBotId, userBotPo.getBotId());
        }
        query.between(ChatBindRecordPo::getCreateTime, LocalDate.now().minusDays(params.getDays() - 1).atStartOfDay(),
                LocalDate.now().atTime(LocalTime.MAX));
        return chatBindRecordMapper.selectList(query);
    }

    /**
     * 倒推天
     */
    private List<String> rangeDate(Integer days) {
        List<String> dateList = new ArrayList<>();
        LocalDate today = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        for (int i = 0; i < days; i++) {
            LocalDate currentDate = today.minusDays(i);
            dateList.add(currentDate.format(formatter));
        }

        return dateList;
    }

}
